home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / realloc.c < prev    next >
C/C++ Source or Header  |  1993-08-16  |  7KB  |  277 lines

  1. /*
  2.  * Copyright 1992 Atari Corporation.
  3.  * All rights reserved.
  4.  */
  5.  
  6. #include "mint.h"
  7.  
  8. /* macro for testing whether a memory region is free */
  9. #define ISFREE(m) ((m)->links == 0)
  10.  
  11. /*
  12.  * long
  13.  * realloc_region(MEMREGION *reg, long newsize):
  14.  * attempt to resize "reg" to the indicated size. If newsize is
  15.  * less than the current region size, the call always
  16.  * succeeds; otherwise, we look for free blocks next to the
  17.  * region, and try to merge these.
  18.  *
  19.  * If newsize == -1L, simply returns the maximum size that
  20.  * the block could be allocated to.
  21.  *
  22.  * Returns: the (physical) address of the new bottom of the
  23.  * region, or 0L if the resize attempt fails.
  24.  *
  25.  * NOTES: if reg == 0, this call does a last-fit allocation
  26.  * of memory of the requested size, and returns a MEMREGION *
  27.  * (cast to a long) pointing at the last region that works
  28.  *
  29.  * This call works ONLY in the "core" memory region (aka ST RAM)
  30.  * and only on non-shared text regions.
  31.  */
  32.  
  33. long
  34. realloc_region(reg, newsize)
  35.     MEMREGION *reg;
  36.     long newsize;
  37. {
  38.     MMAP map;
  39.     MEMREGION *m,*prevptr;
  40.     long oldsize, trysize;
  41.  
  42.     if (newsize != -1L)
  43.         newsize = ROUND(newsize);
  44.     oldsize = reg->len;
  45.  
  46.     if ( reg == 0 || (reg->mflags & M_CORE))
  47.         map = core;
  48.     else {
  49.         return 0;
  50.     }
  51.  
  52. /* last fit allocation: this is pretty straightforward,
  53.  * we just look for the last block that would work
  54.  * and slice off the top part of it.
  55.  * problem: we don't know what the "last block that would fit"
  56.  * is for newsize == -1L, so we look for the biggest block
  57.  */
  58.     if (reg == 0) {
  59.         MEMREGION *lastfit = 0;
  60.         MEMREGION *newm = new_region();
  61.  
  62.         for (m = *map; m; m = m->next) {
  63.             if (ISFREE(m)) {
  64.                 if (newsize == -1L && lastfit
  65.                     && m->len >= lastfit->len)
  66.                     lastfit = m;
  67.                 else if (m->len >= newsize)
  68.                     lastfit = m;
  69.             }
  70.         }
  71.         if (!lastfit)
  72.             return 0;
  73.  
  74.         if (newsize == -1L)
  75.             return lastfit->len;
  76.  
  77.     /* if the sizes match exactly, we save a bit of work */
  78.         if (lastfit->len == newsize) {
  79.             if (newm) dispose_region(newm);
  80.             lastfit->links++;
  81.             mark_region(lastfit, PROT_G);
  82.             return (long)lastfit;
  83.         }
  84.         if (!newm) return 0;    /* can't get a new region */
  85.  
  86.     /* chop off the top "newsize" bytes from lastfit */
  87.     /* and add it to "newm" */
  88.         lastfit->len -= newsize;
  89.         newm->loc = lastfit->loc + lastfit->len;
  90.         newm->len = newsize;
  91.         newm->mflags = lastfit->mflags & M_MAP;
  92.         newm->links++;
  93.         newm->next = lastfit->next;
  94.         lastfit->next = newm;
  95.         mark_region(newm, PROT_G);
  96.         return (long)newm;
  97.     }
  98.  
  99. /* check for trivial resize */
  100.     if (newsize == oldsize) {
  101.         return reg->loc;
  102.     }
  103.  
  104. /*
  105.  * find the block just before ours
  106.  */
  107.     if (*map == reg)
  108.         prevptr = 0;
  109.     else {
  110.         prevptr = *map;
  111.         while (prevptr->next != reg && prevptr) {
  112.             prevptr = prevptr->next;
  113.         }
  114.     }
  115. /*
  116.  * If we're shrinking the block, there's not too much to
  117.  * do (we just free the first "oldsize-newsize" bytes by
  118.  * creating a new region, putting those bytes into it,
  119.  * and freeing it).
  120.  */
  121.     if (newsize < oldsize && newsize != -1L) {
  122.  
  123.         if (prevptr && ISFREE(prevptr)) {
  124. /* add this memory to the previous free region */
  125.             prevptr->len += oldsize - newsize;
  126.             reg->loc += oldsize - newsize;
  127.             reg->len -= oldsize - newsize;
  128.             mark_region(prevptr, PROT_I);
  129.             mark_region(reg, PROT_G);
  130.             return reg->loc;
  131.         }
  132.  
  133. /* make a new region for the freed memory */
  134.         m = new_region();
  135.         if (!m) {
  136.         /* oops, couldn't get a region -- we lose */
  137.         /* punt and pretend we succeeded; after all,
  138.          * we have enough memory!
  139.          */
  140.             return reg->loc;
  141.         }
  142.  
  143.     /* set up the fake region */
  144.         m->links = 0;
  145.         m->mflags = reg->mflags & M_MAP;
  146.         m->loc = reg->loc;
  147.         m->len = oldsize - newsize;
  148.     /* update our region (it's smaller now) */
  149.         reg->loc += m->len;
  150.         reg->len -= m->len;
  151.     /* link the region in just ahead of us */
  152.         if (prevptr)
  153.             prevptr->next = m;
  154.         else
  155.             *map = m;
  156.         m->next = reg;
  157.         mark_region(m, PROT_I);
  158.         mark_region(reg, PROT_G);
  159.         return reg->loc;
  160.     }
  161.  
  162. /* OK, here we have to grow the region: to do this, we first try adding
  163.  * bytes from the region after us (if any) and then the region before
  164.  * us
  165.  */
  166.     trysize = oldsize;
  167.     if (reg->next && ISFREE(reg->next) &&
  168.         (reg->loc + reg->len == reg->next->loc)) {
  169.         trysize += reg->next->len;
  170.     }
  171.     if (prevptr && ISFREE(prevptr) &&
  172.         (prevptr->loc + prevptr->len == reg->loc)) {
  173.         trysize += prevptr->len;
  174.     }
  175.     if (trysize < newsize) {
  176. FORCE("realloc_region: need %ld bytes, only have %ld", trysize, newsize);
  177.         return 0;    /* not enough room */
  178.     }
  179.  
  180.     if (newsize == -1L)    /* size inquiry only?? */
  181.         return trysize;
  182.  
  183. /* BUG: we can be a bit too aggressive at sweeping up
  184.  * memory regions coming after our region; on the other
  185.  * hand, unless something goes seriously wrong there
  186.  * never should *be* any such regions
  187.  */
  188.     if (reg->next && ISFREE(reg->next) && 
  189.         (reg->loc + reg->len == reg->next->loc)) {
  190.         MEMREGION *foo = reg->next;
  191.  
  192.         reg->len += foo->len;
  193.         reg->next = foo->next;
  194.         dispose_region(foo);
  195.         mark_region(reg, PROT_G);
  196.         if (reg->len >= newsize)
  197.             return reg->loc;
  198.         oldsize = reg->len;
  199.     }
  200.     assert(prevptr && ISFREE(prevptr) &&
  201.         prevptr->loc + prevptr->len == reg->loc);
  202.  
  203.     if (newsize > oldsize) {
  204.         reg->loc -= (newsize - oldsize);
  205.         reg->len += (newsize - oldsize);
  206.         prevptr->len -= (newsize - oldsize);
  207.         if (prevptr->len == 0) {
  208.     /* hmmm, we used up the whole region -- we must dispose of the
  209.      * region descriptor
  210.      */
  211.             if (*map == prevptr)
  212.                 *map = prevptr->next;
  213.             else {
  214.                 for (m = *map; m; m = m->next) {
  215.                     if (m->next == prevptr) {
  216.                         m->next = prevptr->next;
  217.                         break;
  218.                     }
  219.                 }
  220.             }
  221.             dispose_region(prevptr);
  222.         }
  223.         mark_region(reg, PROT_G);
  224.     }
  225.  
  226. /* finally! we return the new starting address of "our" region */
  227.     return reg->loc;
  228. }
  229.  
  230.  
  231.  
  232. /*
  233.  * s_realloc emulation: this isn't quite perfect, since the memory
  234.  * used up by the "first" screen will be wasted (we could recover
  235.  * this if we knew the screen start and size, and manually built
  236.  * a region for that screen and linked it into the "core" map
  237.  * (probably at the end))
  238.  * We must always ensure a 256 byte "pad" area is available after
  239.  * the screen (so that it doesn't abut the end of memory)
  240.  */
  241.  
  242. MEMREGION *screen_region = 0;
  243.  
  244. #define PAD 256L
  245.  
  246. long ARGS_ON_STACK
  247. s_realloc(size)
  248.     long size;
  249. {
  250.     long r;
  251.  
  252.     TRACE(("s_realloc(%ld)", size));
  253.  
  254.     if (size != -1L)
  255.         size += PAD;
  256.  
  257.     if (!screen_region) {
  258.         r = realloc_region(screen_region, size);
  259.         if (size == -1L) {    /* inquiry only */
  260.             TRACE(("%ld bytes max srealloc", r-PAD));
  261.             return r - PAD;
  262.         }
  263.         screen_region = (MEMREGION *)r;
  264.         if (!screen_region) {
  265.             DEBUG(("s_realloc: no screen region!!"));
  266.             return 0;
  267.         }
  268.         return screen_region->loc;
  269.     }
  270.     r = realloc_region(screen_region, size);
  271.     if (size == -1L) {
  272.         return r - PAD;
  273.     } else {
  274.         return r;
  275.     }
  276. }
  277.